package com.cby.android.olive.ext

import android.view.LayoutInflater
import android.view.View
import androidx.activity.ComponentActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.viewbinding.ViewBinding
import com.cby.android.olive.recyclerview.ViewBindingRecyclerAdapter
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * @description: ViewBindingExt
 * @author: ChenBaoYang
 * @createDate: 2022/6/27 1:44 下午
 */

/** 针对activity的ViewBinding的拓展委托生成 */
inline fun <reified VB: ViewBinding> ComponentActivity.binding() = lazy{
    inflateBinding<VB>(this.layoutInflater).also {
        setContentView(it.root)
    }
}

/** 针对自己封装好的ViewBindingRecyclerAdapter的ViewBinding的拓展委托生成 */
inline fun <reified VB: ViewBinding, reified T> ViewBindingRecyclerAdapter<VB, T>.binding(): VB = lazy{
    inflateBinding<VB>(this.inflater)
}.value

/** 反射的方式绑定 */
inline fun <reified VB: ViewBinding> inflateBinding(layoutInflater: LayoutInflater) : VB {
    return VB::class.java.getMethod("inflate", LayoutInflater::class.java).invoke(null, layoutInflater) as VB
}

/** 针对Fragment的ViewBinding的拓展委托生成 */
inline fun <reified VB: ViewBinding> Fragment.bind(): VB = lazy {
    VB::class.java.getMethod("bind", View::class.java).invoke(null, requireView()) as VB
}.value

fun <VB : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> VB) =
     FragmentViewBindingDelegate(this, viewBindingFactory)


class FragmentViewBindingDelegate<T : ViewBinding>(
    val fragment: Fragment,
    val viewBindingFactory: (View) -> T
) : ReadOnlyProperty<Fragment, T> {
    private var binding: T? = null

    override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
        val binding = binding
        if (binding != null) {
            return binding
        }
        val lifecycle = fragment.viewLifecycleOwner.lifecycle
        if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
            throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.")
        }
        return viewBindingFactory(thisRef.requireView()).also { this.binding = it }
    }
}
